#pragma once
#include<iostream>
using namespace std;

template <class k>
struct BSTreeNode
{
	BSTreeNode<k>* _left;
	BSTreeNode<k>* _right;
	k _key;

	BSTreeNode(const k& key)
		:_left(nullptr)
		,_right(nullptr)
		,_key(key)
	{}
};

template <class k>
class BSTree
{
	typedef BSTreeNode<k> node;
public:
	bool insert(const k& key)
	{
		if (_root == nullptr)
		{
			_root = new node(key);
			return true;
		}
		node* prev = nullptr;
		node* cur = _root;
		while (cur)
		{
			if (cur->_key < key) prev = cur, cur = cur->_right;
			else if (cur->_key > key) prev = cur, cur = cur->_left;
			else return false;
		}
	
		cur = new node(key);
		if (prev->_key < key) prev->_right = cur;
		else prev->_left = cur;
		return true;
	}

	bool find(const k& key)
	{
		node* cur = _root;
		while (cur)
		{
			if (cur->_key < key) cur = cur->_right;
			else if (cur->_key > key) cur = cur->_left;
			else return true;
		}
		return false;
	}

	bool erase(const k& key)
	{
		node* pcur = nullptr;
		node* cur = _root;
		while (cur)
		{
			if (cur->_key < key) pcur = cur, cur = cur->_right;
			else if (cur->_key > key) pcur = cur, cur = cur->_left;
			else
			{
				if (cur->_left == nullptr)
				{
					if (pcur->_left == cur) pcur->_left = cur->_right;
					else pcur->_right = cur->_right;
					delete cur;
				}
				else if (cur->_right == nullptr)
				{
					if (pcur->_left == cur) pcur->_left = cur->_left;
					else pcur->_right = cur->_left;
					delete cur;
				}
				else
				{
					node* prev = nullptr;
					node* rightmin = cur->_right;
					while (rightmin->_left) prev = rightmin, rightmin = rightmin->_left;
					cur->_key = rightmin->_key;
					if (prev == nullptr) cur->_right = rightmin->_right;
					else prev->_left = rightmin->_right;
					delete rightmin;
				}
				return true;
			}
		}
		return false;
	}

	void inorder()
	{
		_inorder(_root);
		cout << endl;
	}

	void _inorder(node* root)
	{
		if (root == nullptr)
		{
			cout << "N" << " ";
			return;
		}

		_inorder(root->_left);
		cout << root->_key << " ";
		_inorder(root->_right);
	}

private:
	node* _root = nullptr;
};